#include "onetclient.h"
#include "common.h"

OnetClient::OnetClient(QObject *parent, const QString &aNick, const QString &aPassword)
    : QObject(parent), iNick(aNick), iPassword(aPassword), iNickAuth()
{
    iAuth = new Auth(this);
    iConnection = new OnetConnection(this);
//    connect(iAuth, SIGNAL(send(QString)), iConnection, SLOT(Send(QString)));
    connect(iAuth, SIGNAL(send(QString)), this, SLOT(sendRaw(QString)));
    connect(iConnection, SIGNAL(Connected()), SLOT(onSocketConnected()));
    connect(iConnection, SIGNAL(Disconnected()), SLOT(onSocketDisconnected()));
    connect(iConnection, SIGNAL(DataReceived(QString)), SLOT(onReceived(QString)));
    connect(iAuth, SIGNAL(logMessage(QString)), this, SLOT(onLog(QString)));
    if(iNick[0] != '~' && iPassword.isEmpty())
    {
        iNick = QString("~") + iNick;
    }
    if(!iPassword.isEmpty() && iNick[0] == '~')
    {
        iNick = iNick.right(iNick.length()-1);
    }
    iNickAuth = iNick;
    if(iNickAuth[0] == '~')
        iNickAuth = iNickAuth.right(iNick.length()-1);
}

OnetClient::~OnetClient()
{
    delete iConnection;
    delete iAuth;
}

const static QString KOnetServer = "czat-app.onet.pl";
const static quint16 KOnetPort = 5015;

void OnetClient::connectToHost()
{
    logMessage("Connection started...");
    iConnection->Connect(KOnetServer, KOnetPort);
}

void OnetClient::onError(int aError)
{
    logMessage(QString("Connection error %1").arg(aError));
}

void OnetClient::disconnectHost()
{
    iConnection->Disconnect();
}

void OnetClient::onSocketConnected()
{
    emit logMessage("Socket connected");
    iAuth->uoRequest(iNickAuth, iNick, iPassword);
}

void OnetClient::onSocketDisconnected()
{
    emit logMessage("Socket disconnected");
}

void OnetClient::onReceived(QString aMessage)
{
    if(aMessage.endsWith("\r\n"))
        aMessage = aMessage.left(aMessage.length()-2);
    emit logMessage("[RECV] " + aMessage);
    emit rawMessage(aMessage);
    processRaw(aMessage);
}

void OnetClient::sendRaw(QString aRaw)
{
    emit logMessage("[SEND] " + aRaw);
    iConnection->Send(aRaw);
}

void OnetClient::onLog(QString aLog)
{
    emit logMessage("[LOG] " + aLog);
}

void OnetClient::processRaw(const QString &aCmd)
{
    iCmdList = aCmd.split(" ");
    if(iCmdList.count() < 2)
        return;
    if(iCmdList[0] == "ping")
        rawPing();
    else if(iCmdList[1] == "001")
        raw001();
    else if(iCmdList[1] == "801")
        raw801();
    else if(iCmdList[1] == "301")
        raw301();
    else if(iCmdList[1] == "302")
        raw302();
    else if(iCmdList[1] == "305")
        raw305();
    else if(iCmdList[1] == "306")
        raw306();
    else if(iCmdList[1] == "311")
        raw311();
    else if(iCmdList[1] == "312")
        raw312();
    else if(iCmdList[1] == "314")
        raw314();
    else if(iCmdList[1] == "317")
        raw317();
    else if(iCmdList[1] == "353")
        raw353();
    if(iCmdList[1] != "NOTICE" || iCmdList.count() < 4)
        return;
}

void OnetClient::raw001()
{
    sendRaw("PROTOCTL ONETNAMESX");
}

void OnetClient::raw801()
{
    logMessage("801");
    QString s = iCmdList.at(3);
    if(s[0] == ':')
        s = s.right(s.length()-1);
    QString auth = iAuth->transformKey(s);
    if(auth.length() == 16)
    {
        sendRaw("AUTHKEY " + auth);
        QString str = QString("USER * %1 czat-app.onet.pl :%2").arg(iAuth->iUOKey).arg(iAuth->iUONick);
        sendRaw(str);
    }
    else
    {
        logMessage("ERROR: Invalid auth key.");
    }
    emit connected();
}

// :cf1f2.onet 301 scc_test Merovingian :nie ma
void OnetClient::raw301()
{
    if(iCmdList.value(3).isEmpty())
        return;
    QString nick = iCmdList[3];
    QString msg;
    for(int i = 4; i < iCmdList.count(); ++i)
        msg += iCmdList[i] + " ";
    if(msg[0] == ':')
        msg = msg.right(msg.length()-1);
    emit activeMessage(tr("%1 is away: %2").arg(nick).arg(msg));
}

void OnetClient::raw302()
{
    if(iCmdList.value(3).isEmpty())
        return;
    QString msg;
    for(int i = 3; i < iCmdList.length(); ++i)
        msg += iCmdList[i] + " ";
    if(msg[0] == ':')
        msg = msg.right(msg.length()-1);
    emit activeMessage("* " + msg);
}

void OnetClient::raw305()
{
    emit activeMessage(tr("You are no longer marked AWAY"));
}

void OnetClient::raw306()
{
    emit activeMessage(tr("You are marked AWAY"));
}

void OnetClient::raw311()
{
    if(iCmdList.count() < 7)
        return;
    QString nick = iCmdList[3];
    QString zuo = iCmdList[4];
    QString ip = iCmdList[5];
    QString ircname = iCmdList[7];
    for(int i = 8; i < iCmdList.count(); ++i)
        ircname += " " + iCmdList[i];
    if(ircname[0] == ':')
        ircname = ircname.right(ircname.length()-1);
    emit activeMessage(tr("* %1!%2@%3 : %4").arg(nick).arg(zuo).arg(ip).arg(ircname));
}

void OnetClient::raw312()
{
    if(iCmdList.count() < 4)
        return;
    QString nick = iCmdList[3];

    QString server;
    for(int i = 4; i < iCmdList.count(); ++i)
        server += iCmdList[i] + " ";
    emit activeMessage(tr("* %1 is online using %2").arg(nick).arg(server));
}

void OnetClient::raw314()
{
    if(iCmdList.count() < 8)
        return;
    QString nick = iCmdList[3];
    QString zuo = iCmdList[4];
    QString ip = iCmdList[5];
    QString ircname = iCmdList[7];
    if(ircname[0] == ':')
        ircname = ircname.right(ircname.length()-1);
    for(int i = 8; i < iCmdList.count(); ++i)
        ircname += " " + iCmdList[i];
    emit activeMessage(tr("* %1!%2@%3 : %4").arg(nick).arg(zuo).arg(ip).arg(ircname));
}

void OnetClient::raw317()
{
    if(iCmdList.count() < 6)
        return;
    QString nick = iCmdList[3];
    QString idle = iCmdList[4];
    QString time = iCmdList[5];
    idle = FormatTime(idle.toInt());
    QDateTime dt = QDateTime::fromTime_t(time.toInt());
    emit activeMessage(tr("* %1 is away %2").arg(nick).arg(idle));
    emit activeMessage(tr("* %1 is logged in since %2").arg(nick).arg(
            dt.toString(tr("yyyy-MM-dd hh:mm:ss"))
            ));
}

void OnetClient::raw319()
{
    if(iCmdList.count() < 4)
        return;
    QString nick = iCmdList[3];
    QString channels;
    if(iCmdList.count() > 4)
    {
        channels = iCmdList[4];
        if(channels[0] == ':')
            channels = channels.right(channels.length()-1);
        for(int i = 5; i < iCmdList.length(); ++i)
            channels += " " + iCmdList[i];
    }
    emit activeMessage(tr("%1 is on: %2").arg(nick).arg(channels));
}

static void CheckPrefix(QString& cleanedNick, QString& prefix, const QString& what)
{
    if(cleanedNick.contains(what))
    {
        prefix.append(what);
        cleanedNick.remove(what);
    }
}

// 353!
void OnetClient::raw353()
{
    if(iCmdList.count() < 5)
        return;
    QString channel = iCmdList[4];

    for(int i = 5; i < iCmdList.count(); ++i)
    {
        QString nick = iCmdList[i];
        if(i == 5)
            nick = nick.right(nick.length()-1);
        int sepPos = nick.indexOf('|');
        nick = nick.left(sepPos);

        QString suffix = iCmdList[i];
        if(sepPos != -1)
        {
            suffix = suffix.right(suffix.length()-sepPos-1);
            suffix = suffix.left(suffix.length()-2);
        }
        else
            suffix = QString::null;
        QString cleanedNick = nick;
        QString prefix;
        CheckPrefix(cleanedNick, prefix, "`");
        CheckPrefix(cleanedNick, prefix, "@");
        CheckPrefix(cleanedNick, prefix, "%");
        CheckPrefix(cleanedNick, prefix, "!");
        CheckPrefix(cleanedNick, prefix, "=");
        CheckPrefix(cleanedNick, prefix, "+");
        emit registerUser(channel, cleanedNick, prefix, suffix);

        if(channel[0] == '^')
        {
            // priv message, should rename channel->clearedNick
        }
    }
}

void OnetClient::rawPing()
{
    if(iCmdList.count() > 1)
    {
        sendRaw("PONG " + iCmdList[1]);
    }
}




